{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Exporting models from Caffe2 to ONNX\n",
    "\n",
    "In this tutorial we are going to show you how to export a Caffe2 model to ONNX. You can either\n",
    "\n",
    "- Convert a Caffe2 model to an ONNX model in Python\n",
    "\n",
    "or \n",
    "\n",
    "- Convert a Caffe2 model file to an ONNX model file in the shell\n",
    "\n",
    "We are going to use the squeezenet model in Caffe2 model zoo, its model files can be downloaded by running:\n",
    "\n",
    "```shell\n",
    "$ python -m caffe2.python.models.download squeezenet\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Installation\n",
    "\n",
    "`onnx-caffe2` is now integrated as part of `caffe2` under `caffe2/python/onnx`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Note\n",
    "\n",
    "In ONNX, the type and shape of the inputs and outpus are required to be presented in the model, while in Caffe2, they are not stored in the model files. So when doing the convertion, we need to provide these extra information to onnx-caffe2 (through a dictionary in Python/a json string in the shell interface)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exporting in Python"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 0,
   "metadata": {},
   "outputs": [],
   "source": [
    "import onnx\n",
    "import caffe2.python.onnx.frontend\n",
    "from caffe2.proto import caffe2_pb2\n",
    "\n",
    "# We need to provide type and shape of the model inputs, \n",
    "# see above Note section for explanation\n",
    "data_type = onnx.TensorProto.FLOAT\n",
    "data_shape = (1, 3, 224, 224)\n",
    "value_info = {\n",
    "    'data': (data_type, data_shape)\n",
    "}\n",
    "\n",
    "predict_net = caffe2_pb2.NetDef()\n",
    "with open('predict_net.pb', 'rb') as f:\n",
    "    predict_net.ParseFromString(f.read())\n",
    "\n",
    "init_net = caffe2_pb2.NetDef()\n",
    "with open('init_net.pb', 'rb') as f:\n",
    "    init_net.ParseFromString(f.read())\n",
    "\n",
    "onnx_model = caffe2.python.onnx.frontend.caffe2_net_to_onnx_model(\n",
    "    predict_net,\n",
    "    init_net,\n",
    "    value_info,\n",
    ")\n",
    "\n",
    "onnx.checker.check_model(onnx_model)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exporting in shell\n",
    "\n",
    "`onnx-caffe2` has bundled a shell command `convert-caffe2-to-onnx` for exporting Caffe2 model file to ONNX model file.\n",
    "\n",
    "```shell\n",
    "\n",
    "$ convert-caffe2-to-onnx predict_net.pb --caffe2-init-net init_net.pb --value-info '{\"data\": [1, [1, 3, 224, 224]]}' -o sqeezenet.onnx\n",
    "\n",
    "```\n",
    "\n",
    "Regarding to the `--value-info` flag, see above Note section for explanation."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
